/*
 * @(#)DialogTermin.java
 * 1.0, 2013-01-24
 */
package de.hdm.gruppenkalender.team04.gui;

import de.hdm.gruppenkalender.team04.Tools;
import de.hdm.gruppenkalender.team04.data.Alarm;
import de.hdm.gruppenkalender.team04.data.Kalender;
import de.hdm.gruppenkalender.team04.data.Kategorie;
import de.hdm.gruppenkalender.team04.data.Person;
import de.hdm.gruppenkalender.team04.data.Termin;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.rmi.RemoteException;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SpinnerDateModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

/**
 * Aufbau des Termin Dialog mit den diversen Elementen.
 *
 *
 * @author Mathias Bendel (mb167)
 * @author Björn Fichnter (bf023)
 * @author Stefan Hettich (sh176)
 * @author René Kugel (rk044)
 * @author Mark Leonberger (ml072)
 * @author Marta Przybylski (mp070)
 *
 * @version 1.0, 2013-01-24
 *
 */
public class DialogTermin extends JDialog {

    // Termin der gestzt wird, wenn Bearbeiten-Fenster geöffnet wird.
    Termin termin;
    Alarm alarm;
    Vector<Integer> teilnahmen = new Vector<Integer>();
    JTextField txtTitel;
    JSpinner spnStart;
    JSpinner spnEnde;
    JTextField txtOrt;
    JTextField txtBeschreibung;
    JComboBox cbxWiederholung;
    JSpinner spnWiederholung;
    JSpinner spnErinnerung;
    JCheckBox chbErinnerung;
    JComboBox cbxKategorie;
    JComboBox cbxErsteller;
    JComboBox cbxKalender;
    JComboBox cbxTeilnehmer;
    DefaultComboBoxModel comboModelTeilnehmer;
    JButton btnTeilnehmerHinzufuegen;
    JList listTeilnehmer;
    JButton btnTeilnehmerLoeschen;
    DefaultListModel listModelTeilnehmer;
    JButton buttonSpeichern;
    HashMap<String, Kategorie> hashMapKategorie;
    HashMap<String, Kalender> hashMapKalender;
    HashMap<String, Person> hashMapErsteller;
    HashMap<String, Person> hashMapTeilnehmer;
    HashMap<String, Person> hashMapTeilnehmerHinzugefuegt;
    HauptFenster hauptFenster;
    InterfaceClient ic = InterfaceClient.interfaceClient();
    // Aktueller System-Nutzer, ist null, falls Administrator angemeldet.
    Person aktuellerNutzer;
    /**
     * Platzhalter-Strings für die jeweiligen Textfelder.
     */
    private final static String STR_TITEL = "Bitte geben Sie den Titel ein.";
    private final static String STR_ORT = "Bitte geben Sie den Ort ein.";
    private final static String STR_BESCHREIBUNG =
            "Bitte geben Sie die Beschreibung ein.";
    /**
     * ID's zur Idendifikation der Spinner-Objekte.
     */
    private final static int SPINNER_START_ID = 0;
    private final static int SPINNER_ENDE_ID = 1;
    private final static int SPINNER_ERINNERUNG = 2;
    public final static int WIEDERHOLUNG_KEINE = 0;
    public final static int WIEDERHOLUNG_TAG = 1;
    public final static int WIEDERHOLUNG_WOCHE = 2;
    public final static int WIEDERHOLUNG_MONAT = 3;
    public final static int WIEDERHOLUNG_JAHR = 4;

    /**
     * Konstruktor, der das aufrufende Hauptfenster übergibt.
     * 
     * @param hf
     */
    public DialogTermin(HauptFenster hf) {
        this(hf, null);
    }

    /**
     * Konstruktor, der das aufrufende Hauptfenster und den zu
     * bearbeitenden Termin übergibt.
     * <p>
     * Der aktuelle Nutzer wird aus dem HauptFenster ausgelesen und
     * das Erstellen der Elemente wird angestoßen.
     *
     * @param hf
     * @param termin
     */
    public DialogTermin(HauptFenster hf, Termin termin) {
        super(hf, "", true);
        this.hauptFenster = hf;
        this.aktuellerNutzer = hauptFenster.getAktuellerNutzer();
        this.termin = termin;
        this.erstelleElemente();
    }

    /**
     * erstellt das Hauptpanel
     */
    public void erstelleElemente() {
        if (termin == null) {
            this.setTitle("Termin anlegen");
        } else {
            try {
                this.setTitle("Termin '" + termin.getTitel() + "' bearbeiten");
            } catch (RemoteException ex) {
                Logger.getLogger(DialogTermin.class.getName()).log(Level.SEVERE,
                        null, ex);
                this.setTitle("Termin bearbeiten");
            }
        }

        JPanel hauptPanel = erstelleHauptPanel();
        if (hauptPanel != null) {
            this.add(hauptPanel);

            this.setLocation(50, 50);
            this.setResizable(false);

            this.pack();
            this.setVisible(true);
        }
    }

    /**
     * erstellt die GUI-Elemente im HauptPanel und befüllt diese
     * 
     * @return  JPanel  hauptPanel
     */
    public JPanel erstelleHauptPanel() {
        JPanel hauptPanel = new JPanel();

        // Dient zum setzen der Werte in den ComboBoxen.
        String ausgewaehlt = "";

        // GridBagLayout mit Abstand zwischen den Elementen.
        hauptPanel.setLayout(new GridBagLayout());
        GridBagConstraints c = new GridBagConstraints();
        c.fill = GridBagConstraints.HORIZONTAL;
        c.anchor = GridBagConstraints.LINE_START;
        c.insets = new Insets(5, 5, 5, 5);

        // Abstand nach außen erzeugen.
        hauptPanel.setBorder(new EmptyBorder(10, 10, 10, 10));

        /**
         * Textbox und Label für Titel.
         */
        c.gridx = 0;
        c.gridy = 0;
        c.gridwidth = 1;
        hauptPanel.add(new JLabel("Titel:", JLabel.RIGHT), c);
        c.gridx = 1;
        c.gridy = 0;
        c.gridwidth = 2;
        txtTitel = this.erstelleTextFeld(STR_TITEL, true);
        hauptPanel.add(txtTitel, c);


        /**
         * Spinner und Label für Startdatum.
         */
        c.gridx = 0;
        c.gridy = 1;
        c.gridwidth = 1;
        hauptPanel.add(new JLabel("Startdatum:", JLabel.RIGHT), c);

        spnStart = this.erstelleDateSpinner(SPINNER_START_ID);
        c.gridx = 1;
        c.gridy = 1;
        c.gridwidth = 2;
        hauptPanel.add(spnStart, c);

        /**
         * Spinner und Label für Enddatum.
         */
        c.gridx = 0;
        c.gridy = 2;
        c.gridwidth = 1;
        hauptPanel.add(new JLabel("Enddatum:", JLabel.RIGHT), c);
        c.gridx = 1;
        c.gridy = 2;
        c.gridwidth = 2;
        spnEnde = this.erstelleDateSpinner(SPINNER_ENDE_ID);
        hauptPanel.add(spnEnde, c);

        /**
         * TextFeld und Label für Ort.
         */
        c.gridx = 0;
        c.gridy = 3;
        c.gridwidth = 1;
        hauptPanel.add(new JLabel("Ort:", JLabel.RIGHT), c);
        c.gridx = 1;
        c.gridy = 3;
        c.gridwidth = 2;
        txtOrt = this.erstelleTextFeld(STR_ORT, true);
        hauptPanel.add(txtOrt, c);

        /**
         * TextFeld und Label für Beschreibung.
         */
        c.gridx = 0;
        c.gridy = 4;
        c.gridwidth = 1;
        hauptPanel.add(new JLabel("Beschreibung:", JLabel.RIGHT), c);
        c.gridx = 1;
        c.gridy = 4;
        c.gridwidth = 2;
        txtBeschreibung = this.erstelleTextFeld(STR_BESCHREIBUNG, false);
        hauptPanel.add(txtBeschreibung, c);

        /**
         * ComboBox, Spinner und Label für Wiederholung.
         */
        c.gridx = 0;
        c.gridy = 5;
        c.gridwidth = 1;
        hauptPanel.add(new JLabel("Wiederholung (Anzahl):", JLabel.RIGHT), c);
        String[] strWiederholung = {"Keine Wiederholung", "Täglich",
            "Wöchentlich", "Monatlich", "Jährlich"};
        cbxWiederholung = new JComboBox(strWiederholung);
        cbxWiederholung.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                if (cbxWiederholung.getSelectedIndex() == 0) {
                    spnWiederholung.setEnabled(false);
                } else {
                    spnWiederholung.setEnabled(true);
                }
            }
        });
        c.gridx = 1;
        c.gridy = 5;
        c.gridwidth = 1;
        hauptPanel.add(cbxWiederholung, c);

        spnWiederholung = new JSpinner(new SpinnerNumberModel(1, 1, 20, 1));
        spnWiederholung.setEnabled(false);
        c.gridx = 2;
        c.gridy = 5;
        c.gridwidth = 1;
        hauptPanel.add(spnWiederholung, c);

        if (termin != null) {
            int[] statusWiederholungen = ic.ermittleStatusWiederholungen(
                    termin);
            cbxWiederholung.setSelectedIndex(statusWiederholungen[0]);
            if (statusWiederholungen[0] != WIEDERHOLUNG_KEINE) {
                spnWiederholung.setValue(statusWiederholungen[1]);
            } else {
                spnWiederholung.setValue(1);
            }
        }

        /**
         * Spinner, CheckBox und Label für Erinnerung.
         */
        c.gridx = 0;
        c.gridy = 6;
        c.gridwidth = 1;
        hauptPanel.add(new JLabel("Erinnerung:", JLabel.RIGHT), c);

        chbErinnerung = new JCheckBox("Erinnerung setzen?");

        c.gridx = 1;
        c.gridy = 6;
        c.gridwidth = 1;
        spnErinnerung = this.erstelleDateSpinner(SPINNER_ERINNERUNG);
        hauptPanel.add(spnErinnerung, c);

        chbErinnerung.addChangeListener(new ChangeListener() {

            public void stateChanged(ChangeEvent e) {
                if (((JCheckBox) e.getSource()).isSelected()) {
                    spnErinnerung.setEnabled(true);
                } else {
                    spnErinnerung.setEnabled(false);
                }
            }
        });

        c.gridx = 2;
        c.gridy = 6;
        c.gridwidth = 1;
        hauptPanel.add(chbErinnerung, c);

        if (chbErinnerung.isSelected()) {
            spnErinnerung.setEnabled(true);
        } else {
            spnErinnerung.setEnabled(false);
        }

        /**
         * ComboBox und Label für Kategorie.
         */
        c.gridx = 0;
        c.gridy = 7;
        c.gridwidth = 1;
        hauptPanel.add(new JLabel("Kategorie:", JLabel.RIGHT), c);

        ausgewaehlt = "";
        Vector<Kategorie> kategorien = ic.ermittleAlleKategorien();
        if (kategorien.size() < 1) {
            // Wenn es keine Kategorien gibt.
            JOptionPane.showMessageDialog(hauptFenster,
                    "Es existieren keine Kategorien.\n Erstellen Sie " +
                    "zunächst eine Kategorie, oder kontaktieren Sie den " +
                    "Administrator, falls Ihnen die Rechte dazu fehlen.",
                    "Fehler im Datenbestand",
                    JOptionPane.ERROR_MESSAGE);
            return null;
        }
        Vector<String> strKategorie = new Vector<String>();
        hashMapKategorie = new HashMap<String, Kategorie>();
        for (Kategorie kategorie : kategorien) {
            String name = "";
            try {
                name = kategorie.ermittleIdentifikationsName();

                if (termin != null) {
                    if (kategorie.getKategorieId() == termin.getKategorieId()) {
                        ausgewaehlt = name;
                    }
                }
            } catch (RemoteException ex) {
                Logger.getLogger(DialogTermin.class.getName()).
                        log(Level.SEVERE, null, ex);
            }
            strKategorie.add(name);
            hashMapKategorie.put(name, kategorie);
        }
        cbxKategorie = new JComboBox(strKategorie);
        c.gridx = 1;
        c.gridy = 7;
        c.gridwidth = 2;
        hauptPanel.add(cbxKategorie, c);
        if (termin != null) {
            cbxKategorie.setSelectedItem(ausgewaehlt);
        }

        /**
         * Wenn Administrator angemeldet ist, muss ein Ersteller gewählt werden.
         */
        int gridLayoutParam = 0;
        if (aktuellerNutzer == null) {
            /**
             * ComboBox und Label für Ersteller.
             */
            gridLayoutParam = 1;
            c.gridx = 0;
            c.gridy = 8;
            c.gridwidth = 1;
            hauptPanel.add(new JLabel("Ersteller:", JLabel.RIGHT), c);

            ausgewaehlt = "";
            Vector<Person> erstellers = ic.ermittleAllePersonen();
            if (erstellers.size() < 1) {
                // Wenn es keine Personen gibt.
                JOptionPane.showMessageDialog(hauptFenster,
                        "Es existieren keine Personen.\n Erstellen Sie " +
                        "zunächst eine Person.",
                        "Fehler im Datenbestand",
                        JOptionPane.ERROR_MESSAGE);
                return null;
            }
            Vector<String> strErsteller = new Vector<String>();
            hashMapErsteller = new HashMap<String, Person>();
            for (Person ersteller : erstellers) {
                String name = "";
                try {
                    name = ersteller.ermittleIdentifikationsName();
                    if (termin != null) {
                        if (ersteller.getPersonId() == termin.getErstellerId()) {
                            ausgewaehlt = name;
                        }
                    }
                } catch (RemoteException ex) {
                    Logger.getLogger(DialogTermin.class.getName()).
                            log(Level.SEVERE, null, ex);
                }
                strErsteller.add(name);
                hashMapErsteller.put(name, ersteller);
            }
            cbxErsteller = new JComboBox(strErsteller);
            c.gridx = 1;
            c.gridy = 8;
            c.gridwidth = 2;
            hauptPanel.add(cbxErsteller, c);

            if (termin != null) {
                cbxErsteller.setSelectedItem(ausgewaehlt);
            }
        }

        /**
         * ComboBox und Label für Kalender.
         */
        c.gridx = 0;
        c.gridy = 8 + gridLayoutParam;
        c.gridwidth = 1;
        hauptPanel.add(new JLabel("Kalender:", JLabel.RIGHT), c);

        ausgewaehlt = "";
        Vector<Kalender> kalenders = new Vector<Kalender>();

        if (aktuellerNutzer == null) {
            kalenders = ic.ermittleAlleKalender();
        } else {
            // Nur die Kalender von aktueller Nutzer
            kalenders = ic.ermittleAlleKalenderVon(aktuellerNutzer);
        }

        if (kalenders.size() < 1) {
            // Wenn es keine Kalender gibt.
            JOptionPane.showMessageDialog(hauptFenster,
                    "Es existieren keine Kalender.\n Erstellen Sie " +
                    "zunächst einen Kalender.",
                    "Fehler im Datenbestand",
                    JOptionPane.ERROR_MESSAGE);
            return null;
        }
        Vector<String> strKalender = new Vector<String>();
        hashMapKalender = new HashMap<String, Kalender>();
        for (Kalender kalender : kalenders) {
            try {
                String name = kalender.ermittleIdentifikationsName();
                if (termin != null) {
                    if (kalender.getKalenderId() == termin.getKalenderId()) {
                        ausgewaehlt = name;
                    }
                }
                strKalender.add(name);
                hashMapKalender.put(name, kalender);
            } catch (RemoteException ex) {
                Logger.getLogger(DialogTermin.class.getName()).
                        log(Level.SEVERE, null, ex);
            }
        }
        cbxKalender = new JComboBox(strKalender);
        c.gridx = 1;
        c.gridy = 8 + gridLayoutParam;
        c.gridwidth = 2;
        hauptPanel.add(cbxKalender, c);

        if (termin != null) {
            cbxKalender.setSelectedItem(ausgewaehlt);
        }

        /**
         * Teilnehmer-Bereich hinzufügen.
         * Neue Teilnehmer werden über ComboBox hinzugefügt
         * und in der Liste angezeigt und dort ggf. wieder gelöscht.
         */
        c.gridx = 0;
        c.gridy = 9 + gridLayoutParam;
        c.gridwidth = 1;
        hauptPanel.add(new JLabel("Teilnehmer:", JLabel.RIGHT), c);

        Vector<Person> teilnehmer = ic.ermittleAllePersonen();
        if (termin != null) {
            try {
                teilnahmen = termin.getTeilnehmerIds();
            } catch (RemoteException ex) {
                Logger.getLogger(DialogTermin.class.getName()).
                        log(Level.SEVERE, null, ex);
            }
        }
        comboModelTeilnehmer = new DefaultComboBoxModel();
        hashMapTeilnehmer = new HashMap<String, Person>();
        for (Person person : teilnehmer) {
            try {
                if (!teilnahmen.contains(person.getPersonId())) {
                    String name = person.ermittleIdentifikationsName();
                    comboModelTeilnehmer.addElement(name);
                    hashMapTeilnehmer.put(name, person);
                }
            } catch (RemoteException ex) {
                Logger.getLogger(DialogTermin.class.getName()).
                        log(Level.SEVERE, null, ex);
            }
        }
        cbxTeilnehmer = new JComboBox(comboModelTeilnehmer);
        c.gridx = 1;
        c.gridy = 9 + gridLayoutParam;
        c.gridwidth = 1;
        hauptPanel.add(cbxTeilnehmer, c);

        hashMapTeilnehmerHinzugefuegt = new HashMap<String, Person>();
        listModelTeilnehmer = new DefaultListModel();
        for (int personId : teilnahmen) {
            Person p = ic.ermittlePersonViaSchluessel(personId);
            String name = "";
            try {
                name = p.ermittleIdentifikationsName();
            } catch (RemoteException ex) {
                Logger.getLogger(DialogTermin.class.getName()).
                        log(Level.SEVERE, null, ex);
            }
            listModelTeilnehmer.addElement(name);
            hashMapTeilnehmerHinzugefuegt.put(name, p);
        }

        btnTeilnehmerHinzufuegen = new JButton("Teilnehmer hinzufügen");
        btnTeilnehmerHinzufuegen.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                String t = String.valueOf(cbxTeilnehmer.getSelectedItem());
                comboModelTeilnehmer.removeElement(t);

                if (comboModelTeilnehmer.getSize() < 1) {
                    cbxTeilnehmer.setEnabled(false);
                    btnTeilnehmerHinzufuegen.setEnabled(false);
                }

                listModelTeilnehmer.addElement(t);
                sortiereTeilnehmerListe();
                hashMapTeilnehmerHinzugefuegt.put(t, hashMapTeilnehmer.get(t));
                int index = listModelTeilnehmer.indexOf(t);
                listTeilnehmer.setSelectedIndex(index);
                listTeilnehmer.ensureIndexIsVisible(index);
            }
        });
        c.gridx = 2;
        c.gridy = 9 + gridLayoutParam;
        c.gridwidth = 1;
        hauptPanel.add(btnTeilnehmerHinzufuegen, c);

        listTeilnehmer = new JList(listModelTeilnehmer);
        listTeilnehmer.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        listTeilnehmer.setVisibleRowCount(5);
        listTeilnehmer.setSize(0, 100);
        listTeilnehmer.addListSelectionListener(new ListSelectionListener() {

            public void valueChanged(ListSelectionEvent e) {
                if (e.getValueIsAdjusting() == false) {
                    if (listTeilnehmer.getSelectedIndex() == -1) {
                        btnTeilnehmerLoeschen.setEnabled(false);
                    } else {
                        btnTeilnehmerLoeschen.setEnabled(true);
                    }
                }
            }
        });
        JScrollPane listScrollPane = new JScrollPane(listTeilnehmer);
        listScrollPane.setPreferredSize(new Dimension(256, 100));
        c.gridx = 1;
        c.gridy = 10 + gridLayoutParam;
        c.gridwidth = 1;
        hauptPanel.add(listScrollPane, c);
        btnTeilnehmerLoeschen = new JButton("Teilnehmer löschen");
        btnTeilnehmerLoeschen.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                int index = listTeilnehmer.getSelectedIndex();
                String t = listModelTeilnehmer.get(index).toString();
                listModelTeilnehmer.remove(index);
                hashMapTeilnehmerHinzugefuegt.remove(t);

                listTeilnehmer.setSelectedIndex(0);
                listTeilnehmer.ensureIndexIsVisible(index);

                comboModelTeilnehmer.addElement(t);
                if (comboModelTeilnehmer.getSize() > 0) {
                    cbxTeilnehmer.setEnabled(true);
                    btnTeilnehmerHinzufuegen.setEnabled(true);
                }
                sortiereTeilnehmerCombo();
                cbxTeilnehmer.setSelectedIndex(0);
            }
        });
        btnTeilnehmerLoeschen.setEnabled(false);
        c.gridx = 2;
        c.gridy = 10 + gridLayoutParam;
        c.gridwidth = 1;
        hauptPanel.add(btnTeilnehmerLoeschen, c);

        /**
         * Speichern-Button hinzufügen.
         */
        buttonSpeichern = new JButton("Speichern");
        if (termin == null) {
            buttonSpeichern.addActionListener(new ActionListener() {

                public void actionPerformed(ActionEvent e) {
                    // Neuen Termin anlegen.
                    if (!txtTitel.getText().equals("") &&
                            !txtTitel.getText().equals(STR_TITEL) &&
                            !txtOrt.getText().equals("") &&
                            !txtOrt.getText().equals(STR_ORT)) {
                        if (berechneTimestamp(spnStart.getValue()).before(berechneTimestamp(
                                spnEnde.getValue()))) {
                            speichereNeueTermine();
                        } else {
                            zeigeErrorDialog(false);
                        }
                    } else {
                        zeigeErrorDialog(true);
                    }
                }
            });
        } else {
            buttonSpeichern.addActionListener(new ActionListener() {

                public void actionPerformed(ActionEvent e) {
                    if (!txtTitel.getText().equals("") &&
                            !txtTitel.getText().equals(STR_TITEL) &&
                            !txtOrt.getText().equals("") &&
                            !txtOrt.getText().equals(STR_ORT)) {
                        if (berechneTimestamp(spnStart.getValue()).before(berechneTimestamp(
                                spnEnde.getValue()))) {
                            // Termin bearbeiten.
                            int result = Tools.TERMIN_ABBRECHEN_OPTION;

                            result =
                                    JOptionPane.showOptionDialog(
                                    DialogTermin.this,
                                    "Möchten Sie nur diesen Termin oder alle " +
                                    "Termine bearbeiten?",
                                    "Termin bearbeiten",
                                    JOptionPane.DEFAULT_OPTION,
                                    JOptionPane.QUESTION_MESSAGE,
                                    null, Tools.DIALOG_OPTIONEN_TERMIN,
                                    Tools.DIALOG_OPTIONEN_TERMIN[Tools.TERMIN_ABBRECHEN_OPTION]);


                            if (result == Tools.TERMIN_DIESER_OPTION) {
                                /**
                                 * Wenn dieser Termin ein einfacher Termin, ohne
                                 * Wiederholung ist, kann er einfach bearbeitet werden.
                                 *
                                 * Wenn dieser Termin ein einfacher Termin, jedoch mit
                                 * Wiederholung ist, wird dieser aus der "Serie"
                                 * rausgenommen und die Verknüpfung zum Folgetermin
                                 * wird gelöscht. Der Folgetermin wird zu einem
                                 * einfachen Termin gemacht (war Wiederholung).
                                 *
                                 * Wenn dieser Termin eine Wiederholung ist,
                                 * wird dieser aus der "Serie" rausgenommen und der
                                 * Vorgängertermin mit dem Folgetermin verknüpft.
                                 */
                                // Diesen einen Termin löschen.
                                ic.loescheTermin(termin, aktuellerNutzer,
                                        false);
                                speichereNeueTermine();

                            } else if (result == Tools.TERMIN_ALLE_OPTION) {
                                /**
                                 * Alle Termine und Wiederholungen löschen.
                                 *
                                 * Dieser Schritt ist notwendig, da ein Prüfung der
                                 * Änderungen an allen Wiederholungen und Alarmen
                                 * ähnlich aufwendig und deutlich komplexer ist.
                                 * Es werden einfach alle Termine, Wiederholungen und
                                 * Alarme gelöscht und daraufhin mit den geänderten
                                 * Informationen wieder angelegt.
                                 */
                                ic.loescheTermin(termin, aktuellerNutzer, true);
                                // Alles "NEU" speichern.
                                speichereNeueTermine();
                            }
                        } else {
                            zeigeErrorDialog(false);
                        }
                    } else {
                        zeigeErrorDialog(true);
                    }
                }
            });
        }
        c.gridx = 1;
        c.gridy = 11 + gridLayoutParam;
        c.gridwidth = 2;
        hauptPanel.add(buttonSpeichern, c);

        return hauptPanel;
    }

    /**
     * Sortiert die Teilnehmer-JList
     */
    public void sortiereTeilnehmerListe() {
        Vector<String> list = new Vector<String>();
        for (int i = 0; i < listModelTeilnehmer.getSize(); i++) {
            list.add(listModelTeilnehmer.getElementAt(i).toString());
        }

        Collections.sort(list);

        for (int i = 0; i < listModelTeilnehmer.getSize(); i++) {
            listModelTeilnehmer.setElementAt(list.get(i), i);
        }
    }

    /**
     * Sortiert die Teilnehmer-JComboBox
     */
    public void sortiereTeilnehmerCombo() {
        Vector<String> list = new Vector<String>();
        int size = comboModelTeilnehmer.getSize();
        for (int i = 0; i < size; i++) {
            list.add(comboModelTeilnehmer.getElementAt(i).toString());
        }

        Collections.sort(list);

        comboModelTeilnehmer.removeAllElements();
        for (int i = 0; i < size; i++) {
            comboModelTeilnehmer.addElement(list.get(i));
        }
    }

    /**
     * Erstellt ein JTextFeld, das je nach Platzhalter mit Text befüllt wird.
     * Der boolsche Wert dient der Entscheidung, ob immer wieder der Platzhalter
     * im Feld erscheinen soll, wenn dieses leer bleibt oder dieser nur inital
     * erscheinen soll.
     * 
     * @param   platzhalter
     * @param   permanenterPlatzhalter
     * @return  JTextField              mit Text und FocusListener.
     */
    private JTextField erstelleTextFeld(String platzhalter,
            boolean permanenterPlatzhalter) {
        JTextField textFeld = new JTextField();

        if (termin == null) {
            textFeld.setText(platzhalter);
        } else {
            try {
                if (platzhalter.equals(STR_TITEL)) {
                    textFeld.setText(termin.getTitel());
                }
                if (platzhalter.equals(STR_ORT)) {
                    textFeld.setText(termin.getOrt());
                }
                if (platzhalter.equals(STR_BESCHREIBUNG)) {
                    textFeld.setText(termin.getBeschreibung());
                }
            } catch (RemoteException ex) {
                Logger.getLogger(DialogPerson.class.getName()).log(Level.SEVERE,
                        null, ex);
            }
        }

        textFeld.addFocusListener(new TextFeldFocusListener(platzhalter,
                permanenterPlatzhalter));

        return textFeld;
    }

    /**
     * Erstellt eine JSpinner, anhand der Spinner-Id wird der Füllwert des
     * JSpinners bestimmt.
     *
     * @param   spinnerId
     * @return  JSpinner    mit berechneten Werten gefüllt.
     */
    private JSpinner erstelleDateSpinner(int spinnerId) {
        JSpinner spinner = new JSpinner(new SpinnerDateModel());
        spinner.setEditor(new JSpinner.DateEditor(spinner,
                "dd.MM.yyyy HH:mm"));
        Timestamp jetzt = new Timestamp(Calendar.getInstance().getTime().
                getTime());

        if (termin == null) {
            spinner.setValue(jetzt);
            if (spinnerId == SPINNER_ERINNERUNG) {
                chbErinnerung.setSelected(true);
            }
        } else {
            try {
                switch (spinnerId) {
                    case SPINNER_START_ID:
                        spinner.setValue(termin.getStart());
                        break;
                    case SPINNER_ENDE_ID:
                        Timestamp tempEnde = termin.getEnde();
                        if (tempEnde != null) {
                            spinner.setValue(termin.getEnde());
                        } else {
                            spinner.setValue(termin.getStart());
                        }
                        break;
                    case SPINNER_ERINNERUNG:
                        alarm = ic.ermittleAlarmViaSchluessel(termin.
                                getErinnerungId());
                        if (alarm != null) {
                            spinner.setValue(alarm.getStart());
                            chbErinnerung.setSelected(true);
                        } else {
                            spinner.setValue(jetzt);
                            chbErinnerung.setSelected(false);
                        }
                        break;
                }
            } catch (RemoteException ex) {
                Logger.getLogger(DialogPerson.class.getName()).log(Level.SEVERE,
                        null, ex);
            }
        }
        return spinner;
    }

    /**
     * Ermittelt die Id des Ersteller
     * Unterscheidet sich je nachdem, ob Nutzer oder Administrator eingeloggt
     * ist.
     *
     * @return  int Ersteller-Id
     */
    private int ermittleErstellerId() {
        try {
            if (aktuellerNutzer == null) {
                // Admin-Ansicht. Ersteller in Form gewählt.
                return hashMapErsteller.get(cbxErsteller.getSelectedItem().
                        toString()).getPersonId();

            } else {
                // Nutzer angemeldet => Dessen ID.
                return aktuellerNutzer.getPersonId();
            }
        } catch (RemoteException ex) {
            Logger.getLogger(DialogTermin.class.getName()).
                    log(Level.SEVERE, null, ex);
        }

        return 0;
    }

    /**
     * Liest die Teilnahmen aus dem Formular aus und gibt sie in
     * einem Vector<Integer> zurück.
     * 
     * @param   erstellerId
     * @return  Vector<Integer> Teilnehmer-IDs
     */
    private Vector<Integer> ermittleTeilnehmerIds(int erstellerId) {
        Vector<Integer> teilnehmerIds = new Vector<Integer>();
        for (int i = 0; i < listModelTeilnehmer.getSize(); i++) {
            Person p = hashMapTeilnehmerHinzugefuegt.get(
                    listModelTeilnehmer.get(i).toString());
            try {
                teilnehmerIds.add(p.getPersonId());
            } catch (RemoteException ex) {
                Logger.getLogger(DialogTermin.class.getName()).
                        log(Level.SEVERE, null, ex);
            }
        }

        /**
         * Prüfen, ob Ersteller bereits Teilnehmer ist,
         * sonst ebenfalls hinzufügen.
         */
        if (!teilnehmerIds.contains(erstellerId)) {
            teilnehmerIds.add(erstellerId);
        }

        return teilnehmerIds;
    }

    /**
     * Liest die ausgewählte Kategorie aus der Combox-Box aus und gibt
     * die zugehörige Id zurück.
     *
     * @return  int Id der gewählten Kategorie
     */
    private int ermittleKategorieId() {
        try {
            return hashMapKategorie.get(cbxKategorie.getSelectedItem().
                    toString()).getKategorieId();
        } catch (RemoteException ex) {
            Logger.getLogger(DialogTermin.class.getName()).
                    log(Level.SEVERE, null, ex);
        }
        return 0;
    }

    /**
     * Liest den ausgewählten Kalender aus der Combox-Box aus und gibt
     * die zugehörige Id zurück.
     *
     * @return  int Id des gewählten Kalenders
     */
    private int ermittleKalenderId() {
        try {
            return hashMapKalender.get(cbxKalender.getSelectedItem().toString()).
                    getKalenderId();
        } catch (RemoteException ex) {
            Logger.getLogger(DialogTermin.class.getName()).
                    log(Level.SEVERE, null, ex);
        }
        return 0;
    }

    /**
     * Berechnet anhand des übergebenen Combo-Box Items,
     * den Timestamp des Datums mit Hilfe der Calendar-Klasse.
     * 
     * @param   o           Inhalt des Datum-JSpinner.
     * @return  Timestamp   berechnetes Timestamp-Objekt.
     */
    private Timestamp berechneTimestamp(Object o) {
        Calendar c = Calendar.getInstance();
        c.setTime((Date) o);
        return new Timestamp(c.getTime().getTime());
    }

    /**
     * Liest die Erinnerung aus dem JSpinner aus.
     * Gibt null zurück, wenn keine Erinnerung gesetzt werden soll.
     *
     * @return  Timestamp   berechneter Erinnerungs-Timestamp.
     */
    private Timestamp ermittleErinnerungTimestamp() {
        if (chbErinnerung.isSelected()) {
            return berechneTimestamp(spnErinnerung.getValue());
        }
        return null;
    }

    /**
     * Berechnet je nachdem, ob Wiederholungen gewünscht sind, die Anzahl
     * der Wiederholungen.
     * 
     * @return  int Anzahl der Wiederholungen
     */
    private int ermittleAnzahlWiederholung() {
        if (!spnWiederholung.isEnabled()) {
            return 1;
        }
        // Damit i Wiederholung plus 1 Termin erstellt.
        return Integer.parseInt(spnWiederholung.getValue().toString()) + 1;
    }

    /**
     * Berechnet je nach ausgewählten ComboBox-Eintrag,
     * den Abstand der Wiederholungen mit Hilfe der Calendar-Klasse.
     * 
     * @return  int Abstand der Wiederholungen
     */
    private int berechneAbstandWiederholung() {
        switch (cbxWiederholung.getSelectedIndex()) {
            case WIEDERHOLUNG_KEINE:
                return 0;
            case WIEDERHOLUNG_TAG:
                return Calendar.DAY_OF_WEEK;
            case WIEDERHOLUNG_WOCHE:
                return Calendar.WEEK_OF_MONTH;
            case WIEDERHOLUNG_MONAT:
                return Calendar.MONTH;
            case WIEDERHOLUNG_JAHR:
                return Calendar.YEAR;
            default:
                return 0;
        }
    }

    /**
     * Liest die Eingaben aus dem Formular aus und erstellt einen neuen
     * Termin mit ggf. Wiederholungen und zugehörigen Alarmen.
     */
    public void speichereNeueTermine() {
        int erstellerId = ermittleErstellerId();

        ic.erstelleTermine(
                // Startdatum
                berechneTimestamp(spnStart.getValue()),
                // Enddatum
                berechneTimestamp(spnEnde.getValue()),
                // Titel
                txtTitel.getText(),
                // Ort
                txtOrt.getText(),
                // Beschreibungs-Text
                txtBeschreibung.getText(),
                // Kategorie-Id
                ermittleKategorieId(),
                // Ersteller-Id
                erstellerId,
                // Kalender-Id
                ermittleKalenderId(),
                // Teilnehmer
                ermittleTeilnehmerIds(erstellerId),
                // Erinnerung
                ermittleErinnerungTimestamp(),
                // Wiederholungs-Anzahl
                ermittleAnzahlWiederholung(),
                // Wiederholungs-Abstand
                berechneAbstandWiederholung());

        hauptFenster.erstelleTermineVerwaltung();
        hauptFenster.aktualisiereSwingKomponenten();
        hauptFenster.initialisiereTimer();
        setVisible(false);
        dispose();
        JOptionPane.showMessageDialog(hauptFenster, "Termin erfolgreich " +
                "gespeichert!");
    }

    /**
     * Zeigt einen Fehlerdialog, der auf Fehler bei der Formulareingabe
     * aufmerksam machen.
     */
    public void zeigeErrorDialog(boolean istLeeresFeld) {
        String text = "";
        if (istLeeresFeld) {
            text = "Die Felder 'Titel' und 'Ort' dürfen nicht leer sein.";
        } else {
            text = "Start-Datum darf nicht nach dem End-Datum liegen.";
        }
        JOptionPane.showMessageDialog(DialogTermin.this,
                text,
                "Fehler beim Speichern",
                JOptionPane.ERROR_MESSAGE);
    }
}
